home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
fortran.zip
/
WASM.ZIP
/
RTIME.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-05-05
|
15KB
|
550 lines
Title 'Wolfware Assembler Sample Program', 'Resident Time Display'
;=============================================================================
; Resident Time Display
;
; A RAM resident utility which, if active, constantly displays the time in the
; the upper right corner. Once the utility is installed, the time is activated
; or deactivated with Alt-1 (hold down the Alt key and type 1 on the numeric
; keypad, then release the Alt key). The program is inactive when first
; installed. To install, just type:
;
; RTIME
;
; The time is updated about three times a second, in the backround of whatever
; program is presently being executed. The time display overwrites whatever is
; on the screen at that location. The display can only be activated or
; deactivated when the foreground program does keyboard I/O via interrupt 16H.
; This program should be compatible with with most other programs, resident or
; not, but be warned that memory resident programs exist in a world of hazy
; definitions (i.e. they might not work even when they ought to). This utility
; uses about 1065 bytes of memory.
;
; For simplicity, the program assumes that there are 65535 ticks in an hour,
; which is not accurate, as there are actually 65543. This means that the
; displayed time is 8 ticks fast for each hour past midnight. The most that
; the clock is in error occurs just before midnight, when it is 8 * 23 = 184
; ticks, or about 10 seconds fast. As result of this, the time actually runs
; to about 24:00:10 before switching to 00:00:00.
;
; RTIME does not check for graphics modes. If your computer is in graphics
; mode, rather than showing the time, RTIME with show a bunch of random dots.
; You should probably disable RTIME before going into a graphics mode.
Proc Far
Jmp Install ;skip to installation routine
;--- version number
Ver_Hi Equ 1 ;ones digit of version
Ver_Lo Equ 11 ;decimal digit of version
;================================================
; Equates.
True Equ -1 ;true flag
False Equ 0 ;false flag
;--- display location, location of first character of 8 byte string
Row Equ 1 ;row, 1 to 25
Column Equ 73 ;column, 1 to 80
;--- execution parameters
Key Equ 0001h ;int 16H key code to activate, Alt-1
Attribute Equ 70h ;display attribute, reverse video
Count_Set Equ 6 ;wait count, updated 18.2/COUNT_SET = 3/sec
;--- BIOS data, at segment 0
Equip_Flag Equ 0410h ;equipment word
Screen_Col Equ 044ah ;CRT columns
;--- interrupt location, at segement 0
Keyboard Equ 58h ;keyboard fetch, interrupt 16
Timer_Tick Equ 70h ;timer tick vector location, interrupt 1C
;--- clock information
Timer_Low Equ 046ch ;low word of timer, at segment 0
Timer_High Equ 046eh ;high word of timer, at segment 0
Counts_Sec Equ 18 ;counts in second
Counts_Min Equ 1092 ;counts in minute
Counts_Hor Equ 0ffffh ;counts in hour
;--- local stack size, stack just has to handle
;--- local routines and any hardware interrupts
Stack Equ 20 + 20 ;size
;================================================
; Data.
Activated Db False ;activation status, initially off
Counter Db ? ;execution counter, set when activated
Time_Row Dw Row - 1 ;display row
Time_Col Dw Column - 1 ;display column
Stack_Off Dw ? ;storage for stack offset
Stack_Seg Dw ? ;storage for stack segment
Local_Stk Dw Offset End + Stack ;local stack top
Screen_Off Dw ? ;screen offset
Screen_Seg Dw ? ;screen segment
Temp Dw ? ;temporary storage
;--- display string
Tdisplay Label Byte ;start of string
Db '--:--:--'
Tdisplay_End Label Byte ;end of string (to calculate length)
;--- original interrupts
Old_Int16 Label Dword
Dw ? ;offset
Dw ? ;segment
Old_Int1c Label Dword
Dw ? ;offset
Dw ? ;segment
;================================================
; Alternate interrupt 16H (keyboard I/O) to handle
; normal function calls while intercepting display
; activation/deactivation commands. Check for
; command only if read key or get keyboard status
; (functions 0 and 1).
Int16 Proc Far
Sti ;interrupts on
Pushf ;save entry flags
;--- read next key
Or Ah, Ah ;check if read key
Jnz Nonkey ;jump if not
I16get
Seg Cs ;code segment
Call Old_Int16 ;keyboard interrupt
Cmp Ax, Key ;check scan code
Je Subkey ;jump if activate key
Iret
;--- activation key on read
Subkey
Call Toggle_Act ;toggle present setting
Sub Sp, 2 ;simulate flags for interrupt call
Sub Ah, Ah ;read next key function
Jmps I16get ;try again
;--- keyboard status
Nonkey
Cmp Ah, 1 ;check if keyboard status
Jne Nonstat ;jump if not
Popf ;restore entry flags
Pushf ;flags for interrupt call
Seg Cs ;code segment
Call Old_Int16 ;keyboard interrupt
Pushf
Jnz I16chksk ;jump if key in buffer
Popf
Ret 2 ;throw away flags in stack on return
I16chksk
Cmp Ax, Key ;check scan code
Je I16fact ;jump if activate key
Popf
Ret 2 ;throw away flags in stack on return
;--- activation key on status
I16fact
Sub Ah, Ah ;get key function
Sub Sp, 2 ;simulate flags for interrupt call
Seg Cs ;code segment
Call Old_Int16 ;keyboard interrupt, get key
Call Toggle_Act ;toggle present setting
Mov Ah, 1 ;status function
Jmps Nonkey ;try again, flags still on stack
;--- keyboard shift status or unknown function
Nonstat
Seg Cs ;code segment
Call Old_Int16 ;keyboard interrupt, (flags on stack)
Iret
Endp ;Int16
;================================================
; Toggle active setting and reset screen info.
; Clears time display (sets to dashes).
Toggle_Act Proc Near
Seg Cs
Cmp Activated, True ;check if on
Je Actoff ;jump if so, turn off
;--- activate
Seg Cs
Mov Activated, True ;activate
Seg Cs
Mov Counter, Count_Set ;reset counter
Jmps Screenres
;--- deactivate
Actoff Seg Cs
Mov Activated, False ;activate off
;--- reset screen information and clear display
;--- switch to local stack
Screenres Seg Cs
Mov Stack_Seg, Ss ;save stack segment
Seg Cs
Mov Temp, Cs
Seg Cs
Mov Ss, Temp ;new stack segment
Seg Cs
Mov Stack_Off, Sp ;save stack pointer
Seg Cs
Mov Sp, Local_Stk ;new stack
;--- save all registers
Push Ax
Push Bx
Push Cx
Push Dx
Push Di
Push Si
Push Ds
Push Es
Cld ;forward direction
;--- set screen information
Sub Ax, Ax
Mov Ds, Ax ;segement 0
Mov Bx, [Screen_Col] ;screen columns
Mov Ax, 0b800h ;graphics segment
Mov Dx, [Equip_Flag] ;get equipment flag
And Dx, 30h ;mask CRT bits
Cmp Dx, 30h ;check if BW card
Jne Notbw ;jump if not
Mov Ax, 0b000h ;BW segement
Notbw Mov Dx, Cs
Mov Ds, Dx
Mov Es, Dx ;set data segment registers
Mov Screen_Seg, Ax ;save segment
;--- calculate screen offset
Mov Ax, Bx
Sub Dx, Dx
Mul Ax, Time_Row ;row offset
Add Ax, Time_Col ;add for columns
Shl Ax ;times two, account for attribute bytes
Mov Screen_Off, Ax ;save
;--- clear time display (set numbers to dashes)
Mov Ax, 2d2dh ;dashes to clear time and date
Cli ;interrupts off while display
Mov Di, Offset Tdisplay;dislay line
Stosw ;hours
Inc Di
Stosw ;minutes
Inc Di
Stosw ;seconds
Call Display ;display new string
Sti ;interrupts back on
;--- restore registers
Pop Es
Pop Ds
Pop Si
Pop Di
Pop Dx
Pop Cx
Pop Bx
Pop Ax
;--- restore stack
Seg Cs
Mov Sp, Stack_Off ;stack pointer
Seg Cs
Mov Ss, Stack_Seg ;stack segment
Ret
Endp ;Toggle_Act
;================================================
; Alternate interrupt 1CH (timer tick). Executed
; every timer tick (about 18.2 times a second).
;
; One out of COUNT_SET cycles the time is displayed
; to its predetermined location, so the time is
; actually updated 18.2/COUNT_SET times per second.
;
; Each interrupt calls the original timer tick
; interrupt for the benefit of any other routines
; that were using it.
Int1c Proc Near
Cli ;interrupts off
;--- check if activated
Seg Cs
Cmp Activated, True ;check if activated
Je Redischk ;jump if so
Exit Pushf ;flags for interrupt call
Seg Cs
Call Old_Int1c ;call original interrupt
Iret
Redischk Seg Cs
Dec Counter ;decrement counter
Jnz Exit ;jump if not zero
;--- redisplay time
;--- switch to internal stack
Seg Cs
Mov Activated, False ;deactivate
Seg Cs
Mov Stack_Seg, Ss ;save stack segment
Seg Cs
Mov Temp, Cs
Seg Cs
Mov Ss, Temp ;new stack segment
Seg Cs
Mov Stack_Off, Sp ;save stack pointer
Seg Cs
Mov Sp, Local_Stk ;new stack
;--- save all registers
Push Ax
Push Bx
Push Cx
Push Dx
Push Di
Push Si
Push Ds
Push Es
Cld ;forward direction
;--- get time
Sub Ax, Ax
Mov Ds, Ax ;segment 0
Mov Dx,[Timer_High] ;timer high
Mov Ax,[Timer_Low] ;timer low
;--- set time
Mov Bx, Cs
Mov Ds, Bx
Mov Es, Bx ;set segment registers
Mov Counter, Count_Set ;reset counter
Mov Di, Offset Tdisplay ;start of time display string
Mov Bx, Counts_Hor ;counts/hour
Div Ax, Bx ;divide
Call Number_Con ;convert to ASCII and store
Inc Di ;skip colon
Mov Ax, Dx ;remainder is new dividend
Sub Dx, Dx
Mov Bx, Counts_Min ;counts/minute
Div Ax, Bx ;divide
Call Number_Con ;convert to ASCII and store
Inc Di ;skip colon
Mov Ax, Dx ;remainder is new dividend
Sub Dx, Dx
Mov Bx, Counts_Sec ;counts/second
Div Ax, Bx ;divide
Call Number_Con ;convert to ASCII and store
Call Display ;display string to screen
;--- restore registers
Pop Es
Pop Ds
Pop Si
Pop Di
Pop Dx
Pop Cx
Pop Bx
Pop Ax
;--- restore stack
Seg Cs
Mov Sp, Stack_Off ;restore stack pointer
Seg Cs
Mov Ss, Stack_Seg ;restore stack segment
Seg Cs
Mov Activated, True ;reactivate
Jmp Exit ;exit routine
Endp ;Int1c
;================================================
; Convert number in AL to two digit ASCII string
; and store result to DI. Number must be in range
; 0 to 99. DI returns pointing to byte after new
; string.
Number_Con Proc Near
Shl Al
Sub Ah, Ah ;AX gets relative offset
Add Ax, Offset Numbers ;absolute offset
Mov Si, Ax
Movsw ;move word (two byte digits)
Ret
;--- numbers 00 to 60, though the minutes and seconds should only reach
;--- 59, due to slightly inaccurate rounding, the times tend to get to 60
Numbers Label Byte
Db '00010203040506070809'
Db '10111213141516171819'
Db '20212223242526272829'
Db '30313233343536373839'
Db '40414243444546474849'
Db '50515253545556575859'
Db '60'
Endp ;Number_Con
;================================================
; Display the time string to the screen by
; writing it directly to the screen buffer.
Display Proc Near
Mov Ah, Attribute ;display attribute
Mov Cx, Offset Tdisplay_End - Offset Tdisplay ;length
Mov Di, Screen_Off ;offset into screen
Mov Si, Offset Tdisplay ;start of time string
Mov Es, Screen_Seg ;segment of screen
;--- move string to screen buffer
Disloop Lodsb ;load character
Stosw ;store character and attribute
Loop Disloop ;loop CX times
Ret
Endp ;Display
End Label Byte ;end of code and data, start of stack space
;================================================
; Install the alternate interrupts.
Install Proc Near
;--- install new interrupt vectors
Mov Ax, Offset Int16 ;keyboard offset
Mov Bx, Cs ;present segement
Mov Cx, Offset Int1c ;timer offset
Mov Dx, Cs ;present segement
;--- get and save old interrupts
Mov Ax, 3516h ;function and interrupt 16h
Int 21h ;execute
Mov Word Old_Int16, Bx ;offset
Mov Word Old_Int16+2, Es ;segment
Mov Ax, 351ch ;function and interrupt 1ch
Int 21h ;execute
Mov Word Old_Int1c, Bx ;offset
Mov Word Old_Int1c+2, Es ;segment
;--- set new interrupts
Mov Ax, 2516h ;function and interrupt 16h
Mov Dx, Offset Int16 ;keyboard offset
Int 21h ;execute
Mov Ax, 251ch ;function and interrupt 1ch
Mov Dx, Offset Int1c ;timer offset
Int 21h ;execute (and it's activated!)
;--- display message
Mov Dx, Offset Installm ;message location
Mov Ah, 9 ;print string function
Int 21h ;execute
;--- finish up
Mov Dx, Local_Stk ;end of interrupt, top of local stack
Mov Cl, 4
Shr Dx, Cl ;paragraph form
Inc Dx ;allow for fraction of paragraph
Mov Ax, 3100h ;exit function (stay resident)
Int 21h ;execute
;--- message
Installm Db 13,10
Db '[-------------------------------------------]', 13, 10
Db '[ Resident time display utility installed ]', 13, 10
Db '[----------------- Ver '
Db Ver_Hi+'0', '.', Ver_Lo/10+'0', Ver_Lo\10+'0'
Db ' ----------------]', 13, 10
Db '[ press ALT-1 to activate/deactivate ]', 13, 10
Db '[-------------------------------------------]', 13, 10,'$'
Endp ;Install
Endp ;main program